import json
import ctypes
from . import base_config


class LoadLibIoNet:
    libfile = 'io_net.dll'

    def __init__(self):
        self._p_Command = None
        self._p_closepcap = None
        self._p_psetfilter = None
        self._p_openpcap = None
        self._p_creatpcap = None
        self._p_write = None
        self._p_read_byte = None
        self._p_read_pcap = None
        self.__hand_len = 64
        self.handle = (ctypes.c_char * self.__hand_len)()
        self.loadlib(LoadLibIoNet.libfile)

    def loadlib(self, lib_path):
        libhandle = base_config.load_lib(LoadLibIoNet.libfile)

        # int ReadPcap(void* obj, char* type, void *pcap)
        self._p_read_pcap = libhandle.pyReadPcap
        self._p_read_pcap.argtypes = (ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p)
        self._p_read_pcap.restype = ctypes.c_int

        # int ReadByte(void* obj, char* type, void *buffer, int length)
        self._p_read_byte = libhandle.pyReadByte
        self._p_read_byte.argtypes = (ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_int)
        self._p_read_byte.restype = ctypes.c_int

        # int WritePcap(void *obj, int type, char *buffer, int length)
        self._p_write = libhandle.pyWriteByte
        self._p_write.argtypes = (ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_int)
        self._p_write.restype = ctypes.c_int

        # int CreatePcap(const char *devName, void *headle, int length)
        self._p_creatpcap = libhandle.pyCreatePcap
        self._p_creatpcap.argtypes = (ctypes.c_char_p, ctypes.c_void_p, ctypes.c_int)
        self._p_creatpcap.restype = ctypes.c_int

        # int OpenPcap(void *obj);
        self._p_openpcap = libhandle.pyOpenPcap
        self._p_openpcap.argtype = ctypes.c_void_p
        self._p_openpcap.restype = ctypes.c_int

        # int SetFilterPcap(void *obj, const char * szFilter);
        self._p_psetfilter = libhandle.pySetFilterPcap
        self._p_psetfilter.argtypes = (ctypes.c_void_p, ctypes.c_char_p)
        self._p_psetfilter.restype = ctypes.c_int

        # int ClosePcap(void *obj);
        self._p_closepcap = libhandle.pyClosePcap
        self._p_closepcap.argtype = ctypes.c_void_p
        self._p_closepcap.restype = ctypes.c_int

        self._p_Command = libhandle.pyCommand
        self._p_Command.argtypes = (
            ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int)
        self._p_Command.restype = ctypes.c_int

    @property
    def p_creatpcap(self):
        return self._p_creatpcap

    @property
    def p_openpcap(self):
        return self._p_openpcap

    @property
    def p_psetfilter(self):
        return self._p_psetfilter

    @property
    def p_closepcap(self):
        return self._p_closepcap

    @property
    def p_read_pcap(self):
        return self._p_read_pcap

    @property
    def p_read_byte(self):
        return self._p_read_byte

    @property
    def p_write(self):
        return self._p_write

    @property
    def p_Command(self):
        return self._p_Command


class StructReadPcap(ctypes.Structure):
    _fields_ = [
        ("length", ctypes.c_uint),
        ("data", ctypes.c_char_p),
        ("dataobj", ctypes.c_void_p)
    ]


class IoNet:
    def __init__(self):
        self.libpcappolicy = LoadLibIoNet()
        self.__hand_len = 64
        self.handle = (ctypes.c_char * self.__hand_len)()
        self.Create("ts/sms_policy/")
        self.Open()

    def Create(self, devName):
        # self.handle = bytes(64) # handle必须不小于64字节空间
        # Result = pcap_lib.CreatePcap(devName, self.handle, 64)
        result = self.libpcappolicy.p_creatpcap(devName.encode('utf-8'), ctypes.cast(self.handle, ctypes.c_void_p), self.__hand_len)
        return result

    def Open(self):
        # Result = pcap_lib.OpenPcap(self.handle)
        result = self.libpcappolicy.p_openpcap(ctypes.byref(self.handle))
        return result

    def SetFilter(self, szFilter):
        # Result = pcap_lib.SetFilterPcap(self.handle, szFilter)
        result = self.libpcappolicy.p_psetfilter(self.handle, szFilter.encode('utf-8'))
        return result

    def Close(self):
        result = self.libpcappolicy.p_closepcap(self.handle)
        return result

    # --------------------------------------------
    # pcap {
    #   u32         length;    // 4  ----data-length
    #   u8*         data;    // 8/4----data
    #   void*       dataObj; // 8/4----
    # };
    # --------------------------------------------

    def ReadPcap(self, read_type, leng):
        read_pcap = StructReadPcap()
        result = self.libpcappolicy.p_read_pcap(self.handle, read_type, ctypes.byref(read_pcap))
        return result, read_pcap

    def ReadByte(self, read_type, read_buff, leng):
        result = self.libpcappolicy.p_read_byte(self.handle, read_type, read_buff, leng)
        return result

    def ReadBytePcak(self, read_buff, leng):
        result = self.libpcappolicy.p_read_byte(self.handle, 0, read_buff, leng)
        return result

    def ReadByte2(self, read_type, leng):
        read_buff = (ctypes.c_char * (leng + 4))()
        result = self.libpcappolicy.p_read_byte(self.handle, read_type, ctypes.cast(read_buff, ctypes.c_char_p), leng)
        return result, read_buff.value

    def Write(self, write_type, value):
        if isinstance(value, str):
            b_str = str(value).encode('ascii')
        else:
            b_str = str(json.dumps(value)).encode('ascii')
        c_str = ctypes.create_string_buffer(len(b_str) + 4)
        c_str.value = b_str
        result = self.libpcappolicy.p_write(self.handle, write_type, c_str, len(b_str))
        return result

    def Command(self, type, inBuffer, inLeng, outLeng):
        """
        :param type:  注册类型
        :param inBuffer: 传入字符串
        :param inLeng: 传入长度
        :param outLeng: 输出长度
        :return: 返回码，返回值
        """
        b_inbuffer = str((inBuffer)).encode('ascii')
        str_by = ctypes.create_string_buffer(inLeng + 4)
        str_by.value = b_inbuffer
        outBuffer = ctypes.create_string_buffer(outLeng)
        # print(f"Command  type:{type}  inBuffer:{inBuffer}")
        result = self.libpcappolicy.p_Command(self.handle, type, str_by, inLeng, outBuffer, outLeng)
        return result, outBuffer.value

    def _Command(self, type, in_buff, in_leng, out_buff, out_len):
        return self.libpcappolicy.p_Command(self.handle, type, in_buff, in_leng, out_buff, out_len)

    def CommandEx(self, type, inBuffer, inLeng, outBuffer, outLeng):
        result = self.libpcappolicy.p_Command(self.handle, type, inBuffer, inLeng, outBuffer, outLeng)
        return result
